#define _SVID_SOURCE  1
#include <header.h>

/**
 * 假设父进程fork了一个子进程之后, 子进程打开一个文件, 
 * 把这个文件通过本地socket传给父进程, 让父进程能访问向这个文件写一个hello或者world之类的字符
*/

#define INIT_IOVEC(iovs) char str[5] = {0};\
		struct iovec (iovs)[1];\
		(iovs)[0].iov_base = str;\
		(iovs)[0].iov_len = sizeof(str)

#define INIT_CMSGHDR(cms, type) struct cmsghdr *(cms) = (struct cmsghdr *)malloc(CMSG_LEN(sizeof(type)));\
		(cms)->cmsg_len = CMSG_LEN(sizeof(type));\
		(cms)->cmsg_level = SOL_SOCKET;\
		(cms)->cmsg_type = SCM_RIGHTS

#define INIT_MSGHDR(msg, iovs, cms, type) 		struct msghdr msg;\
		__bzero(&msg, sizeof msg);\
		msg.msg_iov = iovs;\
		msg.msg_iovlen = 1;\
		msg.msg_control = cms;\
		msg.msg_controllen = CMSG_LEN(sizeof(type))


int main(int argc, char* argv[]){
	int socket_pair_fd[2];
	socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_pair_fd);

	pid_t pid = fork();
	ERROR_CHECK(pid, -1, "fork");

	if(pid == 0){
		// child
		close(socket_pair_fd[1]);

		// open
		ssize_t file_fd = open("file.txt", O_RDWR | O_APPEND);
		ERROR_CHECK(file_fd, -1, "open");


		// sendmsg file_fd

		// init iovec
		// 每个iovec既一份数据(目前没什么用)
		char str[5] = {0};
		struct iovec iovs[1];
		iovs[0].iov_base = str;
		iovs[0].iov_len = sizeof(str);
		//INIT_IOVEC(iovs);

		// init cmsghdr
		// 辅助数据对象的cmsg_len+cmsg_level+cmg_type+填充字节+数据，不包含辅助数据之间的填充字节
		struct cmsghdr *cms = (struct cmsghdr *)malloc(CMSG_LEN(sizeof(ssize_t)));
		cms->cmsg_len = CMSG_LEN(sizeof(ssize_t));
		cms->cmsg_level = SOL_SOCKET;	/* 协议类型 */
		cms->cmsg_type = SCM_RIGHTS;	/* 传文件描述符 */
		// INIT_CMSGHDR(cms, ssize_t);

		// 这里才是真正要传的文件描述符
		void *p = CMSG_DATA(cms);
		ssize_t *pfd = (ssize_t *)p;
		*pfd = file_fd;

		// init msghdr
		struct msghdr msg;
		__bzero(&msg, sizeof msg);
		msg.msg_iov = iovs;
		msg.msg_iovlen = 1;
		msg.msg_control = cms;
		msg.msg_controllen = CMSG_LEN(sizeof(ssize_t));
		// INIT_MSGHDR(msg, iovs, cms, ssize_t);

		int ret = sendmsg(socket_pair_fd[0], &msg, 0);
		ERROR_CHECK(ret, -1, "sendmsg");


	}else{
		// parent
		close(socket_pair_fd[0]);


		// recvmsg file_fd

		// init iovs
		char buf[1024];
		struct iovec iovs[1];
		iovs[0].iov_base = buf;
		iovs[0].iov_len = sizeof(buf);

		// init cmsghdr
		struct cmsghdr *cms = (struct cmsghdr *)malloc(CMSG_LEN(sizeof(ssize_t)));
		cms->cmsg_len = CMSG_LEN(sizeof(ssize_t));
		cms->cmsg_level = SOL_SOCKET;
		cms->cmsg_type = SCM_RIGHTS;

		// init msghdr
		struct msghdr msg;
		__bzero(&msg, sizeof msg);
		msg.msg_iov = iovs;
		msg.msg_iovlen = 1;
		msg.msg_control = cms;
		msg.msg_controllen = CMSG_LEN(sizeof(ssize_t));

		int ret = recvmsg(socket_pair_fd[1], &msg, 0);
		ERROR_CHECK(ret, -1, "recvmsg");

		void *p =CMSG_DATA(cms);
		size_t *file_fd = (size_t*)p;


		write(*file_fd, "parent", 6);
	}

	return 0;
}